﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Documents
//  File name:	PdfWatermarker.cs
//  Developer:	Solomatov Igor
//  Created:	16.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.IO;
using Microsoft.SharePoint;
using Smart.Common;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace Smart.Documents.Services
{
	public class PdfWatermarker : IPdfWatermarker
	{
		/// <summary>
		/// Add text as the watermark to each page of the source pdf to create a new pdf with text watermark
		/// </summary>
		/// <param name="site"> site to open from and save files to </param>
		/// <param name="sourceFileUrl"> the full path to the source pdf file </param>
		/// <param name="outputFileUrl"> the full path where the watermarked pdf file will be saved to </param>
		/// <param name="watermarkText"> the string array conntaining the text to use as the watermark. Each element is treated as a line in the watermark </param>
		/// <param name="watermarkFont"> the font to use for the watermark. The default font is HELVETICA </param>
		/// <param name="watermarkFontSize"> the size of the font. The default size is 48 </param>
		/// <param name="watermarkFontColor"> the color of the watermark. The default color is blue </param>
		/// <param name="watermarkFontOpacity"> the opacity of the watermark. The default opacity is 0.3 </param>
		/// <param name="watermarkRotation"> the rotation in degree of the watermark. The default rotation is 45 degree </param>
		public virtual bool AddWatermarkText(SPSite site, string sourceFileUrl, string outputFileUrl, string[] watermarkText, BaseFont watermarkFont, float watermarkFontSize,
		                                     BaseColor watermarkFontColor, float watermarkFontOpacity, float watermarkRotation)
		{
			if (site == null) throw new ArgumentNullException("site");
			if (sourceFileUrl == null) throw new ArgumentNullException("sourceFileUrl");

			try
			{
				var sourceData = site.ReadFile(sourceFileUrl);

				if (sourceData == null)
					return false;

				var outputStream = new MemoryStream();

				AddWatermarkText(sourceData, outputStream, watermarkText, watermarkFont, watermarkFontSize, watermarkFontColor, watermarkFontOpacity, watermarkRotation);

				site.SaveFile(outputFileUrl ?? sourceFileUrl, outputStream, true);

				outputStream.Close();
			}
			catch (Exception x)
			{
				H.LX("PdfWatermark.AddWatermarkText.1", x);

				return false;
			}

			return true;
		}

		/// <summary>
		/// Add text as the watermark to each page of the source pdf to create a new pdf with text watermark
		/// </summary>
		/// <param name="site"> site to open from and save files to </param>
		/// <param name="sourceFile"> the full path to the source pdf file </param>
		/// <param name="outputFileUrl"> the full path where the watermarked pdf file will be saved to </param>
		/// <param name="watermarkText"> the string array conntaining the text to use as the watermark. Each element is treated as a line in the watermark </param>
		/// <param name="watermarkFont"> the font to use for the watermark. The default font is HELVETICA </param>
		/// <param name="watermarkFontSize"> the size of the font. The default size is 48 </param>
		/// <param name="watermarkFontColor"> the color of the watermark. The default color is blue </param>
		/// <param name="watermarkFontOpacity"> the opacity of the watermark. The default opacity is 0.3 </param>
		/// <param name="watermarkRotation"> the rotation in degree of the watermark. The default rotation is 45 degree </param>
		public virtual bool AddWatermarkText(SPSite site, SPFile sourceFile, string outputFileUrl, string[] watermarkText, BaseFont watermarkFont, float watermarkFontSize,
		                                     BaseColor watermarkFontColor, float watermarkFontOpacity, float watermarkRotation)
		{
			if (site == null) throw new ArgumentNullException("site");
			if (sourceFile == null) throw new ArgumentNullException("sourceFile");

			try
			{
				var sourceData = sourceFile.OpenBinary(SPOpenBinaryOptions.SkipVirusScan);

				if (sourceData == null)
					return false;

				var outputStream = new MemoryStream();

				AddWatermarkText(sourceData, outputStream, watermarkText, watermarkFont, watermarkFontSize, watermarkFontColor, watermarkFontOpacity, watermarkRotation);

				if (outputFileUrl == null)
					sourceFile.SaveBinary(outputStream);
				else
					site.SaveFile(outputFileUrl, outputStream, true);

				outputStream.Close();
			}
			catch (Exception x)
			{
				H.LX("PdfWatermark.AddWatermarkText.2", x);

				return false;
			}

			return true;
		}

		protected string systemRoot;

		/// <summary>
		/// Load font from Windows
		/// </summary>
		/// <param name="fontFileName">Font file name</param>
		/// <param name="encoding"> Cp1251 </param>
		/// <param name="embedded">BaseFont.EMBEDDED or BaseFont.NOT_EMBEDDED</param>
		public virtual BaseFont LoadFont(string fontFileName, string encoding, bool embedded)
		{
			if (fontFileName.IsNullOrEmpty()) throw new ArgumentNullException("fontFileName");

			if (encoding == null) encoding = "Cp1251";

			if (systemRoot == null)
				systemRoot = Environment.GetEnvironmentVariable("SystemRoot");

			return BaseFont.CreateFont(systemRoot + @"\Fonts\" + fontFileName, encoding, embedded);
		}

		/// <summary>
		/// Add text as the watermark to each page of the source pdf to create a new pdf with text watermark
		/// </summary>
		/// <param name="sourceData"> the full path to the source pdf file </param>
		/// <param name="outputStream"> the full path where the watermarked pdf file will be saved to </param>
		/// <param name="watermarkText"> the string array conntaining the text to use as the watermark. Each element is treated as a line in the watermark </param>
		/// <param name="watermarkFont"> the font to use for the watermark. The default font is HELVETICA </param>
		/// <param name="watermarkFontSize"> the size of the font. The default size is 48 </param>
		/// <param name="watermarkFontColor"> the color of the watermark. The default color is blue </param>
		/// <param name="watermarkFontOpacity"> the opacity of the watermark. The default opacity is 0.3 </param>
		/// <param name="watermarkRotation"> the rotation in degree of the watermark. The default rotation is 45 degree </param>
		protected virtual bool AddWatermarkText(byte[] sourceData, Stream outputStream, string[] watermarkText, BaseFont watermarkFont, float watermarkFontSize,
		                                        BaseColor watermarkFontColor, float watermarkFontOpacity, float watermarkRotation)
		{
			if (sourceData == null) throw new ArgumentNullException("sourceData");
			if (outputStream == null) throw new ArgumentNullException("outputStream");

			try
			{
				var reader = new PdfReader(sourceData);

				var rect = reader.GetPageSizeWithRotation(1);
				var stamper = new PdfStamper(reader, outputStream);

				stamper.Writer.CloseStream = false;

				if (watermarkFont == null)
					watermarkFont = BaseFont.CreateFont(BaseFont.HELVETICA, "Cp1251" /*BaseFont.CP1250*/, BaseFont.NOT_EMBEDDED);

				if (watermarkFontColor == null)
					watermarkFontColor = BaseColor.BLUE;

				var gstate = new PdfGState {FillOpacity = watermarkFontOpacity, StrokeOpacity = watermarkFontOpacity};

				var pageCount = reader.NumberOfPages;

				for (var pageNum = 1; pageNum <= pageCount; pageNum++)
				{
					var overContent = stamper.GetOverContent(pageNum);

					overContent.SaveState();
					overContent.SetGState(gstate);
					overContent.SetColorFill(watermarkFontColor);
					overContent.BeginText();
					overContent.SetFontAndSize(watermarkFont, watermarkFontSize);
					overContent.SetTextMatrix(30, 30);

					var currentY = watermarkText.Length > 1 ? (rect.Height/2) + ((watermarkFontSize*watermarkText.Length)/2) : rect.Height/2;

					for (var line = 0; line <= watermarkText.Length - 1; line++)
					{
						var offset = line > 0 ? (line*watermarkFontSize) + (watermarkFontSize/4)*line : 0f;

						overContent.ShowTextAligned(Element.ALIGN_CENTER, watermarkText[line], rect.Width/2, currentY - offset, watermarkRotation);
					}

					overContent.EndText();
					overContent.RestoreState();
				}

				stamper.Close();
				reader.Close();
			}
			catch (Exception x)
			{
				H.LX("PdfWatermark.AddWatermarkText.W", x);

				return false;
			}

			return true;
		}
	}
}